import 'dart:async';
import 'dart:math';
import 'dart:collection';
import 'package:flutter/material.dart';
import '../data/levels.dart';
import '../model/difficulty.dart';

class SudokuProvider extends ChangeNotifier {
  late List<List<int>> _solution;
  late List<List<int>> _puzzle;
  late List<List<List<int>>> _userInput;
  late List<List<bool>> _isEditable;
  late Difficulty _difficulty;
  int _hintsUsed = 0;
  int _mistakes = 0;
  int _selectedRow = -1;
  int _selectedCol = -1;
  int _selectedNumber = -1;
  bool _isChecking = false;
  bool _gameCompleted = false;
  Duration _elapsedTime = Duration.zero;
  bool _isTimerRunning = false;
  late DateTime _startTime;
  Timer? _timer;
  late List<List<bool>> _isError;

  SudokuProvider() {
    generateNewPuzzle(Difficulty.easy);
  }

  void generateNewPuzzle(Difficulty difficulty) {
    _difficulty = difficulty;
    _solution = _generateSolution();
    _puzzle = _generatePuzzle(difficulty);
    _userInput = List.generate(9, (_) => List.generate(9, (_) => []));
    _isEditable = List.generate(9, (_) => List.generate(9, (_) => false));
    _hintsUsed = 0;
    _mistakes = 0;
    _selectedRow = -1;
    _selectedCol = -1;
    _isChecking = false;
    _gameCompleted = false;
    _elapsedTime = Duration.zero;
    _isTimerRunning = false;
    _isError = List.generate(9, (_) => List.generate(9, (_) => false));

    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        _isEditable[i][j] = _puzzle[i][j] == 0;
      }
    }

    startTimer();
    notifyListeners();
  }

  List<List<int>> _generateSolution() {
    List<List<int>> solution = List.generate(
      9,
      (_) => List.generate(9, (_) => 0),
    );
    _solveSudoku(solution);
    return solution;
  }

  bool _solveSudoku(List<List<int>> board) {
    for (int row = 0; row < 9; row++) {
      for (int col = 0; col < 9; col++) {
        if (board[row][col] == 0) {
          List<int> numbers = List.generate(9, (i) => i + 1);
          numbers.shuffle();
          for (int num in numbers) {
            if (_isValid(board, row, col, num)) {
              board[row][col] = num;
              if (_solveSudoku(board)) {
                return true;
              } else {
                board[row][col] = 0;
              }
            }
          }
          return false;
        }
      }
    }
    return true;
  }

  bool _isValid(List<List<int>> board, int row, int col, int num) {
    for (int i = 0; i < 9; i++) {
      if (board[row][i] == num || board[i][col] == num) {
        return false;
      }
    }

    int startRow = (row ~/ 3) * 3;
    int startCol = (col ~/ 3) * 3;
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        if (board[startRow + i][startCol + j] == num) {
          return false;
        }
      }
    }

    return true;
  }

  List<List<int>> _generatePuzzle(Difficulty difficulty) {
    List<List<int>> puzzle = List.generate(
      9,
      (i) => List.generate(9, (j) => _solution[i][j]),
    );
    int clues = 0;

    switch (difficulty) {
      case Difficulty.easy:
        clues = 50 + Random().nextInt(6); // 40-45 clues
        break;
      case Difficulty.medium:
        clues = 45 + Random().nextInt(6); // 35-40 clues
        break;
      case Difficulty.hard:
        clues = 40 + Random().nextInt(6); // 30-35 clues
        break;
      case Difficulty.high:
        clues = 35 + Random().nextInt(6); // 25-30 clues
        break;
      case Difficulty.superHigh:
        clues = 30 + Random().nextInt(6); // 20-25 clues
        break;
    }

    int cellsToRemove = 81 - clues;
    List<int> positions = List.generate(81, (i) => i);
    positions.shuffle();

    for (int i = 0; i < cellsToRemove; i++) {
      int pos = positions[i];
      int row = pos ~/ 9;
      int col = pos % 9;
      puzzle[row][col] = 0;
    }

    return puzzle;
  }

  void selectCell(int row, int col) {
    if (!_gameCompleted) {
      // Update selected row/col only if editable
      if (_isEditable[row][col]) {
        _selectedRow = row;
        _selectedCol = col;
        _isChecking = false;
      }

      // Determine cell value for highlighting
      int cellValue = -1;
      if (_puzzle[row][col] != 0) {
        cellValue = _puzzle[row][col];
      } else if (_userInput[row][col].length == 1) {
        cellValue = _userInput[row][col].first;
      }

      _selectedNumber = cellValue;
      notifyListeners();
    }
  }

  void clearSelectedCell() {
    if (_selectedRow != -1 &&
        _selectedCol != -1 &&
        _isEditable[_selectedRow][_selectedCol]) {
      bool wasSingle = _userInput[_selectedRow][_selectedCol].length == 1;
      int previousNumber = wasSingle
          ? _userInput[_selectedRow][_selectedCol].first
          : -1;

      _userInput[_selectedRow][_selectedCol].clear();
      _isError[_selectedRow][_selectedCol] = false;

      if (wasSingle && _selectedNumber == previousNumber) {
        _selectedNumber = -1;
      }

      notifyListeners();
    }
  }

  void enterNumber(int number) {
    if (_selectedRow != -1 &&
        _selectedCol != -1 &&
        _isEditable[_selectedRow][_selectedCol]) {
      bool wasSingle = _userInput[_selectedRow][_selectedCol].length == 1;
      int previousNumber = wasSingle
          ? _userInput[_selectedRow][_selectedCol].first
          : -1;

      if (_userInput[_selectedRow][_selectedCol].contains(number)) {
        _userInput[_selectedRow][_selectedCol].remove(number);
      } else {
        _userInput[_selectedRow][_selectedCol].add(number);
        _userInput[_selectedRow][_selectedCol].sort();
      }

      int currentLength = _userInput[_selectedRow][_selectedCol].length;
      if (currentLength == 1) {
        _selectedNumber = _userInput[_selectedRow][_selectedCol].first;
      } else if (currentLength != 1 &&
          wasSingle &&
          _selectedNumber == previousNumber) {
        _selectedNumber = -1;
      }

      _isError[_selectedRow][_selectedCol] = false;
      _checkIfCompleted();
      notifyListeners();
    }
  }

  void useHint() {
    if (_selectedRow != -1 &&
        _selectedCol != -1 &&
        _isEditable[_selectedRow][_selectedCol] &&
        _userInput[_selectedRow][_selectedCol].isEmpty) {
      _userInput[_selectedRow][_selectedCol] = [
        _solution[_selectedRow][_selectedCol],
      ];
      _hintsUsed++;
      _checkIfCompleted();
      notifyListeners();
    }
  }

  void checkSolution() {
    _isChecking = true;
    _mistakes = 0;
    _isError = List.generate(9, (_) => List.generate(9, (_) => false));

    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        if (_isEditable[i][j] && _userInput[i][j].isNotEmpty) {
          if (!_userInput[i][j].contains(_solution[i][j])) {
            _isError[i][j] = true;
            _mistakes++;
          }
        }
      }
    }

    notifyListeners();
  }

  void _checkIfCompleted() {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        if (_isEditable[i][j] &&
            (_userInput[i][j].isEmpty ||
                !_userInput[i][j].contains(_solution[i][j]))) {
          return;
        }
      }
    }
    _gameCompleted = true;
    stopTimer();
    notifyListeners();
  }

  void startTimer() {
    if (!_isTimerRunning) {
      _startTime = DateTime.now();
      _isTimerRunning = true;
      _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
        if (_isTimerRunning) {
          _elapsedTime = DateTime.now().difference(_startTime);
          notifyListeners();
        } else {
          timer.cancel();
        }
      });
    }
  }

  void stopTimer() {
    _isTimerRunning = false;
    _timer?.cancel();
    _timer = null;
  }

  void pauseTimer() {
    if (_isTimerRunning && !_gameCompleted) {
      _isTimerRunning = false;
      _timer?.cancel();
      _timer = null;
      // 更新已用时间
      _elapsedTime = DateTime.now().difference(_startTime);
    }
  }

  void resumeTimer() {
    if (!_isTimerRunning && !_gameCompleted) {
      // 重新设置开始时间，减去已用时间
      _startTime = DateTime.now().subtract(_elapsedTime);
      _isTimerRunning = true;
      _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
        if (_isTimerRunning) {
          _elapsedTime = DateTime.now().difference(_startTime);
          notifyListeners();
        } else {
          timer.cancel();
        }
      });
    }
  }

  String getFormattedTime() {
    int minutes = _elapsedTime.inMinutes;
    int seconds = _elapsedTime.inSeconds % 60;
    return '$minutes:${seconds.toString().padLeft(2, '0')}';
  }

  // Getters
  List<List<int>> get puzzle =>
      UnmodifiableListView(_puzzle.map((row) => UnmodifiableListView(row)));
  List<List<List<int>>> get userInput => UnmodifiableListView(
    _userInput.map(
      (row) =>
          UnmodifiableListView(row.map((cell) => UnmodifiableListView(cell))),
    ),
  );
  List<List<bool>> get isEditable =>
      UnmodifiableListView(_isEditable.map((row) => UnmodifiableListView(row)));
  List<List<bool>> get isError =>
      UnmodifiableListView(_isError.map((row) => UnmodifiableListView(row)));
  int get selectedRow => _selectedRow;
  int get selectedCol => _selectedCol;

  int get selectedNumber => _selectedNumber;
  int get hintsUsed => _hintsUsed;
  int get mistakes => _mistakes;
  bool get isChecking => _isChecking;
  bool get gameCompleted => _gameCompleted;
  String get difficultyText {
    switch (_difficulty) {
      case Difficulty.easy:
        return '炼气期';
      case Difficulty.medium:
        return '筑基期';
      case Difficulty.hard:
        return '结丹期';
      case Difficulty.high:
        return '元婴期';
      case Difficulty.superHigh:
        return '化神期';
    }
  }

  void loadLevel(Difficulty difficulty, int level) {
    // 先停止之前的计时器
    stopTimer();

    _difficulty = difficulty;
    _puzzle = List.generate(
      9,
      (i) => List<int>.from(levelPuzzles[difficulty]![level - 1][i]),
    );
    _solution = List.generate(9, (i) => List<int>.from(_puzzle[i]));
    _solveSudoku(_solution); // 生成解
    _userInput = List.generate(9, (_) => List.generate(9, (_) => []));
    _isEditable = List.generate(9, (_) => List.generate(9, (_) => false));
    _hintsUsed = 0;
    _mistakes = 0;
    _selectedRow = -1;
    _selectedCol = -1;
    _isChecking = false;
    _gameCompleted = false;
    _elapsedTime = Duration.zero;
    _isTimerRunning = false;
    _isError = List.generate(9, (_) => List.generate(9, (_) => false));
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        _isEditable[i][j] = _puzzle[i][j] == 0;
      }
    }
    startTimer();
    notifyListeners();
  }

  @override
  void dispose() {
    stopTimer();
    super.dispose();
  }
}
